#ifndef __FMOD__AudioManager__
#define __FMOD__AudioManager__


#include "fmod.hpp"
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <map>

using namespace FMOD;

struct AudioRawBuffer
{
	size_t size;
	char* buffer;
	int audioId;
};

class Audio{
private:
	Sound* sound;
	Channel* freePlay;
	float orgFrequency;
	double length;
	float volume;
public:
	explicit Audio();
	~Audio();
	void init();
	void play();
	void pause();
	void stop();
	void toggle();

	void seek(double position);
	void setVolume(float volume);

	double getTime();
	double getLength();
	double getSampleRate();

	friend class AudioManager;
	friend class Track;
};

class TrackCell{
public:
	Audio* audio;
	Channel* channel;
	float volume;
	int offset;
	explicit TrackCell();
	void stop();
};

class Track{
private:
	System* system;
	ChannelGroup* group;
	double length;
	unsigned int cellCount;
	std::vector<TrackCell*> cells;
	long long startDspClock;
	int bufSize; // 提前多久开始排队播放
	int prevBufPos; // 上一次处理到哪里。cell->offset <= prevBufPos的已经排队播放
	int sampleRate;
	float speed;
	TrackCell * getCell(unsigned int tid);
	void updateCell(TrackCell * cell); // 在修改cell或播放时间时，重设cell播放状态及位置
public:
	explicit Track();
	~Track();
	void clear();
	void init();
	void update();
	void play();
	void resume();
	void pause();
	void toggle();
	bool isPlaying();
	void seek(double position);
	void setVolume(float volume);
	void setSpeed(float speed);
	bool isCellValid(unsigned int tid);
	int addCell(Audio* audio);
	void removeCell(unsigned int tid);
	void setCellOffset(unsigned int tid, double time);
	void setCellVolume(unsigned int tid, float volume);
	void setLength(double len);
	double getTime();
	double getLength();
	double getBufTime();

	friend class AudioManager;
};

class AudioManager{
private:
    System* system;
    std::vector<Audio*> samples;
	std::vector<Track*> tracks;
	std::map<std::string, AudioRawBuffer> audioBuffers;
	int sampleRate;

	AudioManager();
    ~AudioManager();

    static AudioManager* instance;
public:
    static AudioManager* getInstance();
	static bool releaseInstance();

	void update();

	double getDSPDelay();

	//对audio操作
    int load(const char *filename);
	void release(unsigned int index);
	void prepare(unsigned int index);
    Audio* getAudio(unsigned int index);

	//对track操作
	int createTrack();
	void releaseTrack(unsigned int index);
	Track* getTrack(unsigned int index);

    static unsigned int dspBufferLength;
    static int dspNumBuffers;
};

#endif
